
public class Parser {
	String nmea_string, nmea_type;


	public static double sog=-1; 
	public static double cog=-1;
	public static double aws,awd,tws,twd,twa;

	public Parser () {
		super();
	}

	public void parse(String string){
		nmea_string= string;
		double a,b;
		double y,bb;
		boolean aa;
		// check nmea checksum
		if (check(nmea_string)){
			//	check that it is really a begin of a standard NMEA sentence					
			if ( nmea_string.substring(0,1).equals("$")) {
				String nmea_array[] = nmea_string.split(",");

				//				this might be necessary if data has spaces or s.o.else		
				//				for (int i=0; i<nmea_array.length; i++) 
				//    					nmea_array[i].trim();

				//check for specific sentences if there is s.th. to do)
				nmea_type = nmea_array[0].substring(3,6);
				if (nmea_type.equals("RMC")) {
					sog = Double.valueOf(nmea_array[7]).floatValue();
					cog = Double.valueOf(nmea_array[8]).floatValue();
					System.out.println ("PARSER:    SOG=" + sog +" COG="+ cog);
				}
				else if (nmea_type.equals("MWV")) {

					if (nmea_array[2].equals("R")){
						aws = Double.valueOf(nmea_array[3]).floatValue();
						awd = Double.valueOf(nmea_array[1]).floatValue();
						System.out.println ("PARSER:    AWS=" + aws +" AWD="+ awd );
						if (sog > -1) {
							y = 90 - awd;
							a = aws * Math.cos(Math.toRadians(y));
							bb= aws * Math.sin(Math.toRadians(y));
							b = bb - sog;
							tws= Math.sqrt(a*a+b*b);
							if (Math.abs(a)< 0.01) {
								if ((sog <= aws) && ((Math.abs(awd) < 1) || (Math.abs(awd) > 359))) {
									twd = 0 ;
								}
								else{
									twd = 180;
								}
							}

							else {
								twd= 90 - Math.toDegrees(Math.atan(b/a));
								if (awd > 180) twd = twd +180;
							}
							twa = twd + cog;
							if (twa > 360) twa= twa-360;
							System.out.println ("PARSER:    SOG=" + sog +" COG="+ cog +" ==> TWS=" + tws +" TWD="+ twd +" TWA="+twa);
						}
					}

					else if (nmea_array[2].equals("T")){
						tws = Double.valueOf(nmea_array[3]).floatValue();
						twd = Double.valueOf(nmea_array[1]).floatValue();
						twa = twd + cog;
						if (twa > 360) twa= twa-360;
						System.out.println ("PARSER:    TWS=" + tws +" TWD="+ twd +" TWA="+twa);
						if (sog > -1) {
							y = 90 - twd;
							a = tws * Math.cos(Math.toRadians(y));
							b= tws * Math.sin(Math.toRadians(y));
							bb = b + sog;
							aws= Math.sqrt(a*a+bb*bb);
							if (Math.abs(a)< 0.01) {
								if ((sog >= tws) && (Math.abs((Math.abs(twd)-180))<1)){
									awd = 0 ;
								}
								else
								{
									awd = 180;
								}
							}
							else {
								awd= 90 - Math.toDegrees(Math.atan(bb/a));
								if (twd > 180) awd = awd +180;
							}
							System.out.println ("PARSER:    SOG=" + sog + " COG="+ cog +" ==> AWS=" + aws +" AWD="+ awd);
						}
					}
				}
			}
		}
	}


	/** calculates checksum of NMEA message and compares it
	 * 
	 * 
	 * @param msg
	 * @return true if the checksum is valid, false if it is invalid
	 */
	private boolean check(String msg) {

		boolean IAmValid = false;

		//calculate message length and subtract one (the carriage return)
		int msglen = msg.length() - 1;

		//if the message length is greater than 4 characters
		if (msglen > 4) {
			//check if there is a checksum in this message by seeing where the asterisk is
			//(it should be at the third last position in the message)
			if (msg.charAt(msglen - 3) == '*') {
				//  System.out.println("    received checksum : " + msg.substring(msglen - 2, msglen));
				// perform NMEA checksum calculation
				String chk_s = GetCheckSum(msg.substring(0, msglen - 3));

				// compare checksum to encoded checksum in msg
				IAmValid = msg.substring(msglen - 2, msglen).equals(chk_s);
				if (!IAmValid) System.out.println("PARSER:    Checksum: message checksum is wrong (should be "+chk_s+" )");
				return (IAmValid);
			} else {
				// message doesn't have a checksum: do not accept it
				System.out.println("PARSER:    Checksum: message has no checksum.");
				return false;
			}
		}
		//(if the message length is greater than 4 characters)
		// don't accept messages without checksum
		return false;
	}


	/**
	 * Trims the checksum off an NMEA message, then
	 * recalculates the checksum
	 * to compare it with the one passed along with the message later
	 * 
	 * @param msg String containing the full NMEA message (including checksum)
	 * @return String containing the checksum
	 */
	public static String GetCheckSum(String msg) {
		// perform NMEA checksum calculation
		int chk = 0;
		//run through each character of the message length
		//and XOR the value of chk with the byte value
		//of the character that is being evaluated
		for (int i = 1; i < msg.length(); i++) {
			chk ^= msg.charAt(i);
		}

		//convert the retreived integer to a HexString in uppercase
		String chk_s = Integer.toHexString(chk).toUpperCase();

		// checksum must be 2 characters!
		// if it falls short, add a zero before the checksum
		while (chk_s.length() < 2) {
			chk_s = "0" + chk_s;
		}

		//show the calculated checksum
		// System.out.println("    calculated checksum : " + chk_s);

		//return the calculated checksum
		return chk_s;
	}	
}
